home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 1843 / 1843.xpi / content / firebug / commandLine.js < prev    next >
Text File  |  2010-01-15  |  32KB  |  1,036 lines

  1. /* See license.txt for terms of usage */
  2.  
  3. FBL.ns(function() { with (FBL) {
  4.  
  5. // ************************************************************************************************
  6. // Constants
  7. const Cc = Components.classes;
  8. const Ci = Components.interfaces;
  9.  
  10. const commandHistoryMax = 1000;
  11. const commandPrefix = ">>>";
  12.  
  13. const reOpenBracket = /[\[\(\{]/;
  14. const reCloseBracket = /[\]\)\}]/;
  15. const reCmdSource = /^with\(_FirebugCommandLine\){(.*)};$/;
  16.  
  17. // ************************************************************************************************
  18. // GLobals
  19.  
  20. var commandHistory = [""];
  21. var commandPointer = 0;
  22. var commandInsertPointer = -1;
  23.  
  24. // ************************************************************************************************
  25.  
  26. Firebug.CommandLine = extend(Firebug.Module,
  27. {
  28.     dispatchName: "commandLine",
  29.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  30.  
  31.     // targetWindow was needed by evaluateInSandbox, let's leave it for a while in case we rethink this yet again
  32.  
  33.     initializeCommandLineIfNeeded: function (context, win)
  34.     {
  35.       if (context == null) return;
  36.       if (win == null) return;
  37.  
  38.       // The command-line requires that the console has been initialized first,
  39.       // so make sure that's so.  This call should have no effect if the console
  40.       // is already initialized.
  41.       var consoleIsReady = Firebug.Console.isReadyElsePreparing(context, win);
  42.  
  43.       // Make sure the command-line is initialized.  This call should have no
  44.       // effect if the command-line is already initialized.
  45.       var commandLineIsReady = Firebug.CommandLine.isReadyElsePreparing(context, win);
  46.  
  47.     },
  48.  
  49.     evaluate: function(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction) // returns user-level wrapped object I guess.
  50.     {
  51.         if (!context)
  52.             return;
  53.  
  54.         var debuggerState = Firebug.Debugger.beginInternalOperation();
  55.         try
  56.         {
  57.             var result = null;
  58.  
  59.             if (context.stopped)
  60.             {
  61.                 result = this.evaluateInDebugFrame(expr, context, thisValue, targetWindow,  successConsoleFunction, exceptionFunction);
  62.             }
  63.             else
  64.             {
  65.                 result = this.evaluateByEventPassing(expr, context, thisValue, targetWindow,  successConsoleFunction, exceptionFunction);
  66.             }
  67.  
  68.             context.invalidatePanels('dom', 'html');
  69.         }
  70.         catch (exc)  // XXX jjb, I don't expect this to be taken, the try here is for the finally
  71.         {
  72.         }
  73.         finally
  74.         {
  75.             Firebug.Debugger.endInternalOperation(debuggerState);
  76.         }
  77.  
  78.         return result;
  79.     },
  80.  
  81.     evaluateByEventPassing: function(expr, context, thisValue, targetWindow, successConsoleFunction, exceptionFunction)
  82.     {
  83.         var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window );
  84.         if (!win)
  85.         {
  86.             return;
  87.         }
  88.  
  89.         // We're going to use some command-line facilities, but it may not have initialized yet.
  90.         this.initializeCommandLineIfNeeded(context, win);
  91.  
  92.         // Make sure the command line script is attached.
  93.         var element = Firebug.Console.getFirebugConsoleElement(context, win);
  94.         if (element)
  95.         {
  96.             var attached = element.getAttribute("firebugCommandLineAttached");
  97.             if (!attached)
  98.             {
  99.                 FBTrace.sysout("Firebug console element does not have command line attached its too early for command line", element);
  100.                 Firebug.Console.logFormatted(["Firebug cannot find firebugCommandLineAttached attribute on firebug console element, its too early for command line", element, win], context, "error", true);
  101.                 return;
  102.             }
  103.         }
  104.         else
  105.         {
  106.             return;  // we're in trouble here
  107.         }
  108.  
  109.         var event = document.createEvent("Events");
  110.         event.initEvent("firebugCommandLine", true, false);
  111.         element.setAttribute("methodName", "evaluate");
  112.  
  113.         expr = expr.toString();
  114.         expr = "with(_FirebugCommandLine){" + expr + "\n};";
  115.         element.setAttribute("expr", expr);
  116.  
  117.         var consoleHandler;
  118.         for (var i=0; i<context.activeConsoleHandlers.length; i++)
  119.         {
  120.             if (context.activeConsoleHandlers[i].window == win)
  121.             {
  122.                 consoleHandler = context.activeConsoleHandlers[i];
  123.                 break;
  124.             }
  125.         }
  126.  
  127.         if (successConsoleFunction)
  128.         {
  129.             consoleHandler.evaluated = function useConsoleFunction(result)
  130.             {
  131.                 successConsoleFunction(result, context);  // result will be pass thru this function
  132.             }
  133.         }
  134.  
  135.         if (exceptionFunction)
  136.         {
  137.             consoleHandler.evaluateError = function useExceptionFunction(result)
  138.             {
  139.                 exceptionFunction(result, context);
  140.             }
  141.         }
  142.         else
  143.         {
  144.             consoleHandler.evaluateError = function useErrorFunction(result)
  145.             {
  146.                 if (result)
  147.                 {
  148.                     var m = reCmdSource.exec(result.source);
  149.                     if (m && m.length > 0)
  150.                         result.source = m[1];
  151.                 }
  152.  
  153.                 Firebug.Console.logFormatted([result], context, "error", true);
  154.             }
  155.         }
  156.  
  157.         element.dispatchEvent(event);
  158.     },
  159.  
  160.     evaluateInDebugFrame: function(expr, context, thisValue, targetWindow,  successConsoleFunction, exceptionFunction)
  161.     {
  162.         var result = null;
  163.  
  164.         // targetWindow may be frame in HTML
  165.         var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window );
  166.  
  167.         if (!context.commandLineAPI)
  168.             context.commandLineAPI = new FirebugCommandLineAPI(context, (win.wrappedJSObject?win.wrappedJSObject:win));  // TODO should be baseWindow
  169.  
  170.         var htmlPanel = context.getPanel("html", true);
  171.         var scope = {
  172.             api       : context.commandLineAPI,
  173.             vars      : htmlPanel?htmlPanel.getInspectorVars():null,
  174.             thisValue : thisValue
  175.         };
  176.  
  177.         try
  178.         {
  179.             result = Firebug.Debugger.evaluate(expr, context, scope);
  180.             successConsoleFunction(result, context);  // result will be pass thru this function
  181.         }
  182.         catch (e)
  183.         {
  184.             exceptionFunction(e, context);
  185.         }
  186.         return result;
  187.     },
  188.  
  189.     //
  190.     evaluateInWebPage: function(expr, context, targetWindow)
  191.     {
  192.         var win = targetWindow ? targetWindow : context.window;
  193.         var doc = (win.wrappedJSObject ? win.wrappedJSObject.document : win.document);
  194.         var element = addScript(doc, "_firebugInWebPage", expr);
  195.         element.parentNode.removeChild(element);  // we don't need the script element, result is in DOM object
  196.         return "true";
  197.     },
  198.  
  199.     // TODO: strip down to minimum, have one global sandbox that is reused.
  200.     evaluateInSandbox: function(expr, context, thisValue, targetWindow, skipNotDefinedMessages)  // returns user-level wrapped object I guess.
  201.     {
  202.         // targetWindow may be frame in HTML
  203.         var win = targetWindow ? targetWindow : ( context.baseWindow ? context.baseWindow : context.window );
  204.  
  205.         if (!context.sandboxes)
  206.             context.sandboxes = [];
  207.  
  208.         if (win.wrappedJSObject) //  XPCNativeWrapper vs  XPCSafeJSObjectWrapper
  209.         {
  210.             // in FF3.1, this path fails.
  211.             var sandbox = new Components.utils.Sandbox(win.location.toString());
  212.             //sandbox.__proto__ = win.wrappedJSObject;
  213.             sandbox.__proto__ = win;
  214.         }
  215.         else
  216.         {
  217.             // in FF3.1, this path works
  218.             var sandbox = new Components.utils.Sandbox(win); // Use DOM Window
  219.             sandbox.__proto__ = win;
  220.         }
  221.  
  222.         var scriptToEval = expr;
  223.  
  224.         // If we want to use a specific |this|, wrap the expression with Function.apply()
  225.         // and inject the new |this| into the sandbox so it's easily accessible.
  226.         if (thisValue) {
  227.             // XXXdolske is this safe if we're recycling the sandbox?
  228.             sandbox.__thisValue__ = thisValue;
  229.             scriptToEval = "(function() { return " + scriptToEval + " \n}).apply(__thisValue__);";
  230.         }
  231.  
  232.         // Page scripts expect |window| to be the global object, not the
  233.         // sandbox object itself. Stick window into the scope chain so
  234.         // assignments like |foo = bar| are effectively |window.foo =
  235.         // bar|, else the page won't see the new value.
  236.         scriptToEval = "with (window?window:null) { " + scriptToEval + " \n};";
  237.  
  238.         try {
  239.             result = Components.utils.evalInSandbox(scriptToEval, sandbox);
  240.         } catch (e) {
  241.             result = new FBL.ErrorMessage("commandLine.evaluateInSandbox FAILED: " + e, FBL.getDataURLForContent(scriptToEval, "FirebugCommandLineEvaluate"), e.lineNumber, 0, "js", context, null);
  242.         }
  243.         return result;
  244.     },
  245.  
  246.     getSandboxByWindow: function(context, win)
  247.     {
  248.         for (var i = 0; i < context.sandboxes.length; i++) {
  249.             // XXXdolske is accessing .window safe after untrusted script has run?
  250.             if (context.sandboxes[i].window === win.wrappedJSObject)
  251.                 return context.sandboxes[i];
  252.         }
  253.         return null;
  254.     },
  255.  
  256.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  257.  
  258.     enter: function(context, command)
  259.     {
  260.         var commandLine = getCommandLine(context);
  261.         var expr = command ? command : commandLine.value;
  262.         if (expr == "")
  263.             return;
  264.         var MozJSEnabled = navigator.preference("javascript.enabled");
  265.  
  266.         if(MozJSEnabled)
  267.         {
  268.             if (!Firebug.largeCommandLine)
  269.             {
  270.                 this.clear(context);
  271.                 this.appendToHistory(expr);
  272.                 Firebug.Console.log(commandPrefix + " " + expr, context, "command", FirebugReps.Text);
  273.             }
  274.             else
  275.             {
  276.                 var shortExpr = cropString(stripNewLines(expr), 100);
  277.                 Firebug.Console.log(commandPrefix + " " + shortExpr, context, "command", FirebugReps.Text);
  278.             }
  279.  
  280.             var goodOrBad = FBL.bind(Firebug.Console.log, Firebug.Console);
  281.  
  282.             var noscript = getNoScript();
  283.             var uri = noscript && noscript.getSite(Firebug.chrome.getCurrentURI().spec);
  284.  
  285.             if(noscript && !(noscript.jsEnabled || noscript.isJSEnabled(uri)))
  286.             {
  287.  
  288.                 noscript.setJSEnabled(uri, true);
  289.                 this.evaluate(expr, context, null, null, goodOrBad);
  290.                 noscript.setJSEnabled(uri, false);
  291.             }
  292.             else
  293.                 this.evaluate(expr, context, null, null, goodOrBad);
  294.         }
  295.         else
  296.             Firebug.Console.log($STR("console.JSDisabledInFirefoxPrefs"), context, "info");
  297.     },
  298.  
  299.     enterMenu: function(context)
  300.     {
  301.         var commandLine = getCommandLine(context);
  302.         var expr = commandLine.value;
  303.         if (expr == "")
  304.             return;
  305.  
  306.         this.appendToHistory(expr, true);
  307.  
  308.         this.evaluate(expr, context, null, null, function(result, context)
  309.         {
  310.             if (typeof(result) != "undefined")
  311.             {
  312.                 Firebug.chrome.contextMenuObject = result;
  313.  
  314.                 var popup = Firebug.chrome.$("fbContextMenu");
  315.                 popup.showPopup(commandLine, -1, -1, "popup", "bottomleft", "topleft");
  316.             }
  317.         });
  318.     },
  319.  
  320.     enterInspect: function(context)
  321.     {
  322.         var commandLine = getCommandLine(context);
  323.         var expr = commandLine.value;
  324.         if (expr == "")
  325.             return;
  326.  
  327.         this.clear(context);
  328.         this.appendToHistory(expr);
  329.  
  330.         this.evaluate(expr, context, null, null, function(result, context)
  331.         {
  332.             if (typeof(result) != undefined)
  333.                 Firebug.chrome.select(result);
  334.         });
  335.     },
  336.  
  337.     reenter: function(context)
  338.     {
  339.         var command = commandHistory[commandInsertPointer];
  340.         if (command)
  341.             this.enter(context, command);
  342.     },
  343.  
  344.     copyBookmarklet: function(context)
  345.     {
  346.         var commandLine = getCommandLine(context);
  347.         var expr = "javascript: " + stripNewLines(commandLine.value);
  348.         copyToClipboard(expr);
  349.     },
  350.  
  351.     focus: function(context)
  352.     {
  353.         if (Firebug.isDetached())
  354.             Firebug.chrome.focus();
  355.         else
  356.             Firebug.toggleBar(true);
  357.  
  358.         if (!context.panelName)
  359.             Firebug.chrome.selectPanel("console");
  360.         else if (context.panelName != "console")
  361.         {
  362.             Firebug.chrome.switchToPanel(context, "console");
  363.  
  364.             var commandLine = getCommandLine(context);
  365.             setTimeout(function() { commandLine.select(); });
  366.         }
  367.         else // then we are already on the console, toggle back
  368.         {
  369.             Firebug.chrome.unswitchToPanel(context, "console", true);
  370.         }
  371.     },
  372.  
  373.     clear: function(context)
  374.     {
  375.         var commandLine = getCommandLine(context);
  376.         commandLine.value = context.commandLineText = "";
  377.         this.autoCompleter.reset();
  378.     },
  379.  
  380.     cancel: function(context)
  381.     {
  382.         var commandLine = getCommandLine(context);
  383.         if (!this.autoCompleter.revert(commandLine))
  384.             this.clear(context);
  385.     },
  386.  
  387.     update: function(context)
  388.     {
  389.         var commandLine = getCommandLine(context);
  390.         context.commandLineText = commandLine.value;
  391.         this.autoCompleter.reset();
  392.     },
  393.  
  394.     complete: function(context, reverse)
  395.     {
  396.         var commandLine = getCommandLine(context);
  397.         this.autoCompleter.complete(context, commandLine, true, reverse);
  398.         context.commandLineText = commandLine.value;
  399.     },
  400.  
  401.     setMultiLine: function(multiLine, chrome, saveMultiLine)
  402.     {
  403.         if (FirebugContext && FirebugContext.panelName != "console")
  404.             return;
  405.  
  406.         collapse(chrome.$("fbCommandBox"), multiLine);
  407.         collapse(chrome.$("fbPanelSplitter"), !multiLine);
  408.         collapse(chrome.$("fbSidePanelDeck"), !multiLine);
  409.  
  410.         if (multiLine)
  411.             chrome.$("fbSidePanelDeck").selectedPanel = chrome.$("fbLargeCommandBox");
  412.  
  413.         var commandLineSmall = chrome.$("fbCommandLine");
  414.         var commandLineLarge = chrome.$("fbLargeCommandLine");
  415.  
  416.         if (saveMultiLine)  // we are just closing the view
  417.         {
  418.             commandLineSmall.value = commandLineLarge.value;
  419.             return;
  420.         }
  421.  
  422.         if (multiLine)
  423.             commandLineLarge.value = cleanIndentation(commandLineSmall.value);
  424.         else
  425.             commandLineSmall.value = stripNewLines(commandLineLarge.value);
  426.     },
  427.  
  428.     toggleMultiLine: function(forceLarge)
  429.     {
  430.         var large = forceLarge || !Firebug.largeCommandLine;
  431.         if (large != Firebug.largeCommandLine)
  432.             Firebug.setPref(Firebug.prefDomain, "largeCommandLine", large);
  433.     },
  434.  
  435.     checkOverflow: function(context)
  436.     {
  437.         if (!context)
  438.             return;
  439.  
  440.         var commandLine = getCommandLine(context);
  441.         if (commandLine.value.indexOf("\n") >= 0)
  442.         {
  443.             setTimeout(bindFixed(function()
  444.             {
  445.                 Firebug.setPref(Firebug.prefDomain, "largeCommandLine", true);
  446.             }, this));
  447.         }
  448.     },
  449.  
  450.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  451.  
  452.     appendToHistory: function(command, unique)
  453.     {
  454.         if (unique && commandHistory[commandInsertPointer] == command)
  455.             return;
  456.  
  457.         ++commandInsertPointer;
  458.         if (commandInsertPointer >= commandHistoryMax)
  459.             commandInsertPointer = 0;
  460.  
  461.         commandPointer = commandInsertPointer+1;
  462.         commandHistory[commandInsertPointer] = command;
  463.     },
  464.  
  465.     cycleCommandHistory: function(context, dir)
  466.     {
  467.         var commandLine = getCommandLine(context);
  468.  
  469.         commandHistory[commandPointer] = commandLine.value;
  470.  
  471.         if (dir < 0)
  472.         {
  473.             --commandPointer;
  474.             if (commandPointer < 0)
  475.                 commandPointer = 0;
  476.         }
  477.         else
  478.         {
  479.             ++commandPointer;
  480.             if (commandPointer > commandInsertPointer+1)
  481.                 commandPointer = commandInsertPointer+1;
  482.         }
  483.  
  484.         var command = commandHistory[commandPointer];
  485.  
  486.         this.autoCompleter.reset();
  487.  
  488.         commandLine.value = context.commandLineText = command;
  489.         commandLine.inputField.setSelectionRange(command.length, command.length);
  490.     },
  491.  
  492.     // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  493.     // extends Module
  494.  
  495.     initialize: function()
  496.     {
  497.         Firebug.Module.initialize.apply(this, arguments);
  498.  
  499.         this.autoCompleter = new Firebug.AutoCompleter(getExpressionOffset, getDot,
  500.             autoCompleteEval, false, true);
  501.  
  502.         if (Firebug.largeCommandLine)
  503.             this.setMultiLine(true, Firebug.chrome);
  504.     },
  505.  
  506.     initializeUI: function()
  507.     {
  508.         this.attachListeners();
  509.     },
  510.  
  511.     reattachContext: function(browser, context)
  512.     {
  513.         this.attachListeners();
  514.     },
  515.  
  516.     attachListeners: function()
  517.     {
  518.         Firebug.chrome.$("fbLargeCommandLine").addEventListener('focus', this.onCommandLineFocus, true);
  519.         Firebug.chrome.$("fbCommandLine").addEventListener('focus', this.onCommandLineFocus, true);
  520.  
  521.         Firebug.Console.addListener(this);  // to get onConsoleInjection
  522.     },
  523.  
  524.     showContext: function(browser, context)
  525.     {
  526.         var command = Firebug.chrome.$("cmd_focusCommandLine");
  527.         command.setAttribute("disabled", !context);
  528.     },
  529.  
  530.     showPanel: function(browser, panel)
  531.     {
  532.         var chrome = Firebug.chrome;
  533.  
  534.         var isConsole = panel && panel.name == "console";
  535.         if (Firebug.largeCommandLine)
  536.         {
  537.             if (isConsole)
  538.             {
  539.                 collapse(chrome.$("fbPanelSplitter"), false);
  540.                 collapse(chrome.$("fbSidePanelDeck"), false);
  541.                 chrome.$("fbSidePanelDeck").selectedPanel = chrome.$("fbLargeCommandBox");
  542.                 collapse(chrome.$("fbCommandBox"), true);
  543.             }
  544.         }
  545.         else
  546.             collapse(chrome.$("fbCommandBox"), !isConsole);
  547.  
  548.         var value = panel ? panel.context.commandLineText : null;
  549.         var commandLine = getCommandLine(browser);
  550.         commandLine.value = value ? value : "";
  551.     },
  552.  
  553.     updateOption: function(name, value)
  554.     {
  555.         if (name == "largeCommandLine")
  556.             this.setMultiLine(value, Firebug.chrome);
  557.     },
  558.  
  559.     // called by users of command line, currently:
  560.     // 1) Console on focus command line, 2) Watch onfocus, and 3) debugger loadedContext if watches exist
  561.     isReadyElsePreparing: function(context, win)
  562.     {
  563.         if (win)
  564.             Firebug.CommandLine.injector.attachCommandLine(context, win);
  565.         else
  566.         {
  567.             Firebug.CommandLine.injector.attachCommandLine(context, context.window);
  568.             for (var i = 0; i < context.windows.length; i++)
  569.                 Firebug.CommandLine.injector.attachCommandLine(context, context.windows[i]);
  570.         }
  571.  
  572.         if (!context.window.wrappedJSObject)
  573.         {
  574.             FBTrace.sysout("context.window with no wrappedJSObject!", context.window);
  575.             return false;
  576.         }
  577.  
  578.         // the attach is asynchronous, we can report when it is complete:
  579.         if (context.window.wrappedJSObject._FirebugCommandLine)
  580.             return true;
  581.         else
  582.             return false;
  583.     },
  584.  
  585.     onCommandLineFocus: function(event)
  586.     {
  587.         Firebug.CommandLine.attachConsoleOnFocus();
  588.  
  589.         if (!Firebug.CommandLine.isAttached(FirebugContext))
  590.         {
  591.             return Firebug.CommandLine.isReadyElsePreparing(FirebugContext);
  592.         }
  593.         else
  594.         {
  595.             return true; // is attached.
  596.         }
  597.     },
  598.  
  599.     isAttached: function(context)
  600.     {
  601.         return context && context.window && context.window.wrappedJSObject && context.window.wrappedJSObject._FirebugCommandLine;
  602.     },
  603.  
  604.     attachConsoleOnFocus: function()
  605.     {
  606.         if (!FirebugContext)
  607.         {
  608.             return;
  609.         }
  610.  
  611.         if (Firebug.Console.isReadyElsePreparing(FirebugContext))
  612.         {
  613.             // the page had _firebug so we know that consoleInjected.js compiled and ran.
  614.         }
  615.         else
  616.         {
  617.             Firebug.Console.injector.forceConsoleCompilationInPage(FirebugContext, FirebugContext.window);
  618.  
  619.         }
  620.     },
  621.  
  622.     onPanelEnable: function(panelName)
  623.     {
  624.         collapse(Firebug.chrome.$("fbCommandBox"), true);
  625.         collapse(Firebug.chrome.$("fbPanelSplitter"), true);
  626.         collapse(Firebug.chrome.$("fbSidePanelDeck"), true);
  627.  
  628.         this.setMultiLine(Firebug.largeCommandLine, Firebug.chrome);
  629.     },
  630.  
  631.     onPanelDisable: function(panelName)
  632.     {
  633.         if (panelName != 'console')  // we don't care about other panels
  634.             return;
  635.  
  636.         collapse(Firebug.chrome.$("fbCommandBox"), true);
  637.         collapse(Firebug.chrome.$("fbPanelSplitter"), true);
  638.         collapse(Firebug.chrome.$("fbSidePanelDeck"), true);
  639.     },
  640.  
  641.     // *********************************************************************************************
  642.     // Firebug.Console listener
  643.     onConsoleInjected: function(context, win)
  644.     {
  645.         // for some reason the console has been injected. If the user had focus in the command line they want it added in the page also.
  646.         // If the user has the cursor in the command line and reloads, the focus will already be there. issue 1339
  647.         var isFocused = ($("fbLargeCommandLine").getAttribute("focused") == "true");
  648.         isFocused = isFocused || ($("fbCommandLine").getAttribute("focused") == "true");
  649.         if (isFocused)
  650.             setTimeout(this.onCommandLineFocus);
  651.     },
  652. });
  653.  
  654. // ************************************************************************************************
  655. // Shared Helpers
  656.  
  657. Firebug.CommandLine.CommandHandler = extend(Object,
  658. {
  659.     handle: function(event, api, win)
  660.     {
  661.         var element = event.target;
  662.         var methodName = element.getAttribute("methodName");
  663.  
  664.         var hosed_userObjects = (win.wrappedJSObject?win.wrappedJSObject:win)._firebug.userObjects;
  665.  
  666.         var userObjects = hosed_userObjects ? cloneArray(hosed_userObjects) : [];
  667.  
  668.         var subHandler = api[methodName];
  669.         if (!subHandler)
  670.             return false;
  671.  
  672.         element.removeAttribute("retValueType");
  673.         var result = subHandler.apply(api, userObjects);
  674.         if (typeof result != "undefined")
  675.         {
  676.             if (result instanceof Array)
  677.             {
  678.                 element.setAttribute("retValueType", "array");
  679.                 for (var item in result)
  680.                     hosed_userObjects.push(result[item]);
  681.             }
  682.             else
  683.             {
  684.                 hosed_userObjects.push(result);
  685.             }
  686.         }
  687.  
  688.         return true;
  689.     }
  690. });
  691.  
  692. // ************************************************************************************************
  693. // Local Helpers
  694.  
  695. function getExpressionOffset(command, offset)
  696. {
  697.     // XXXjoe This is kind of a poor-man's JavaScript parser - trying
  698.     // to find the start of the expression that the cursor is inside.
  699.     // Not 100% fool proof, but hey...
  700.  
  701.     var bracketCount = 0;
  702.  
  703.     var start = command.length-1;
  704.     for (; start >= 0; --start)
  705.     {
  706.         var c = command[start];
  707.         if ((c == "," || c == ";" || c == " ") && !bracketCount)
  708.             break;
  709.         if (reOpenBracket.test(c))
  710.         {
  711.             if (bracketCount)
  712.                 --bracketCount;
  713.             else
  714.                 break;
  715.         }
  716.         else if (reCloseBracket.test(c))
  717.             ++bracketCount;
  718.     }
  719.  
  720.     return start + 1;
  721. }
  722.  
  723. function getDot(expr, offset)
  724. {
  725.     var lastDot = expr.lastIndexOf(".");
  726.     if (lastDot == -1)
  727.         return null;
  728.     else
  729.         return {start: lastDot+1, end: expr.length-1};
  730. }
  731.  
  732. function autoCompleteEval(preExpr, expr, postExpr, context)
  733. {
  734.     try
  735.     {
  736.         if (preExpr)
  737.         {
  738.             // Remove the trailing dot (if there is one)
  739.             var lastDot = preExpr.lastIndexOf(".");
  740.             if (lastDot != -1)
  741.                 preExpr = preExpr.substr(0, lastDot);
  742.  
  743.             var self = this;
  744.             Firebug.CommandLine.evaluate(preExpr, context, context.thisValue, null,
  745.                 function found(result, context)
  746.                 {
  747.                     self.complete = keys(result).sort();
  748.                 },
  749.                 function failed(result, context)
  750.                 {
  751.                     self.complete = [];
  752.                 }
  753.             );
  754.             return self.complete;
  755.         }
  756.         else
  757.         {
  758.             if (context.stopped)
  759.                 return Firebug.Debugger.getCurrentFrameKeys(context);
  760.             else
  761.                 return keys(context.window.wrappedJSObject).sort();  // return is safe
  762.         }
  763.     }
  764.     catch (exc)
  765.     {
  766.         return [];
  767.     }
  768. }
  769.  
  770. function injectScript(script, win)
  771. {
  772.     win.location = "javascript: " + script;
  773. }
  774.  
  775. // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * *
  776.  
  777. function getCommandLine(context)
  778. {
  779.     return Firebug.largeCommandLine
  780.         ? Firebug.chrome.$("fbLargeCommandLine")
  781.         : Firebug.chrome.$("fbCommandLine");
  782. }
  783.  
  784. const reIndent = /^(\s+)/;
  785.  
  786. function getIndent(line)
  787. {
  788.     var m = reIndent.exec(line);
  789.     return m ? m[0].length : 0;
  790. }
  791.  
  792. function cleanIndentation(text)
  793. {
  794.     var lines = splitLines(text);
  795.  
  796.     var minIndent = -1;
  797.     for (var i = 0; i < lines.length; ++i)
  798.     {
  799.         var line = lines[i];
  800.         var indent = getIndent(line);
  801.         if (minIndent == -1 && line && !isWhitespace(line))
  802.             minIndent = indent;
  803.         if (indent >= minIndent)
  804.             lines[i] = line.substr(minIndent);
  805.     }
  806.     return lines.join("");
  807. }
  808.  
  809. // ************************************************************************************************
  810. // Command line APIs definition
  811.  
  812. function FirebugCommandLineAPI(context, baseWindow)
  813. {
  814.     this.$ = function(id)
  815.     {
  816.         var doc = baseWindow.document;
  817.         return baseWindow.document.getElementById(id);
  818.     };
  819.  
  820.     this.$$ = function(selector)
  821.     {
  822.         return FBL.getElementsBySelector(baseWindow.document, selector);
  823.     };
  824.  
  825.     this.$x = function(xpath)
  826.     {
  827.         return FBL.getElementsByXPath(baseWindow.document, xpath);
  828.     };
  829.  
  830.     this.$n = function(index)
  831.     {
  832.         var htmlPanel = context.getPanel("html", true);
  833.         if (!htmlPanel)
  834.             return null;
  835.  
  836.         if (index < 0 || index >= htmlPanel.inspectorHistory.length)
  837.             return null;
  838.  
  839.         var node = htmlPanel.inspectorHistory[index];
  840.         if (!node)
  841.             return node;
  842.  
  843.         return node.wrappedJSObject;
  844.     };
  845.  
  846.     this.cd = function(object)
  847.     {
  848.         if (!(object instanceof Window))
  849.             throw "Object must be a window.";
  850.  
  851.         // The window object parameter uses XPCSafeJSObjectWrapper, but we need XPCNativeWrapper
  852.         // (and its wrappedJSObject member). So, look within all registered consoleHandlers for
  853.         // the same window (from tabWatcher) that uses uses XPCNativeWrapper (operator "==" works).
  854.         for (var i=0; i<context.activeConsoleHandlers.length; i++) {
  855.             if (context.activeConsoleHandlers[i].window == object) {
  856.                 baseWindow = context.baseWindow = context.activeConsoleHandlers[i].window;
  857.                 break;
  858.             }
  859.         }
  860.  
  861.         Firebug.Console.log(["Current window:", context.baseWindow], context, "info");
  862.     };
  863.  
  864.     this.clear = function()
  865.     {
  866.         Firebug.Console.clear(context);
  867.     };
  868.  
  869.     this.inspect = function(obj, panelName)
  870.     {
  871.         Firebug.chrome.select(obj, panelName);
  872.     };
  873.  
  874.     this.keys = function(o)
  875.     {
  876.         return FBL.keys(o);
  877.     };
  878.  
  879.     this.values = function(o)
  880.     {
  881.         return FBL.values(o);
  882.     };
  883.  
  884.     this.debug = function(fn)
  885.     {
  886.         Firebug.Debugger.monitorFunction(fn, "debug");
  887.     };
  888.  
  889.     this.undebug = function(fn)
  890.     {
  891.         Firebug.Debugger.unmonitorFunction(fn, "debug");
  892.     };
  893.  
  894.     this.monitor = function(fn)
  895.     {
  896.         Firebug.Debugger.monitorFunction(fn, "monitor");
  897.     };
  898.  
  899.     this.unmonitor = function(fn)
  900.     {
  901.         Firebug.Debugger.unmonitorFunction(fn, "monitor");
  902.     };
  903.  
  904.     this.traceAll = function()
  905.     {
  906.         Firebug.Debugger.traceAll(FirebugContext);
  907.     };
  908.  
  909.     this.untraceAll = function()
  910.     {
  911.         Firebug.Debugger.untraceAll(FirebugContext);
  912.     };
  913.  
  914.     this.traceCalls = function(fn)
  915.     {
  916.         Firebug.Debugger.traceCalls(FirebugContext, fn);
  917.     };
  918.  
  919.     this.untraceCalls = function(fn)
  920.     {
  921.         Firebug.Debugger.untraceCalls(FirebugContext, fn);
  922.     };
  923.  
  924.     this.monitorEvents = function(object, types)
  925.     {
  926.         monitorEvents(object, types, context);
  927.     };
  928.  
  929.     this.unmonitorEvents = function(object, types)
  930.     {
  931.         unmonitorEvents(object, types, context);
  932.     };
  933.  
  934.     this.profile = function(title)
  935.     {
  936.         Firebug.Profiler.startProfiling(context, title);
  937.     };
  938.  
  939.     this.profileEnd = function()
  940.     {
  941.         Firebug.Profiler.stopProfiling(context);
  942.     };
  943.  
  944.     this.copy = function(x)
  945.     {
  946.         FBL.copyToClipboard(x);
  947.     };
  948. }
  949.  
  950. // ************************************************************************************************
  951.  
  952. Firebug.CommandLine.injector = {
  953.  
  954.     attachCommandLine: function(context, win)
  955.     {
  956.         if (!win)
  957.             return;
  958.  
  959.         // If the command line is already attached then end.
  960.         var doc = win.document;
  961.         if ($("_firebugCommandLineInjector", doc))
  962.             return;
  963.  
  964.         if (context.stopped)
  965.             Firebug.CommandLine.injector.evalCommandLineScript(context);
  966.         else
  967.             Firebug.CommandLine.injector.injectCommandLineScript(doc);
  968.  
  969.         Firebug.CommandLine.injector.addCommandLineListener(context, win, doc);
  970.     },
  971.  
  972.     evalCommandLineScript: function(context)
  973.     {
  974.         var scriptSource = getResource("chrome://firebug/content/commandLineInjected.js");
  975.         Firebug.Debugger.evaluate(scriptSource, context);
  976.     },
  977.  
  978.     injectCommandLineScript: function(doc)
  979.     {
  980.         // Inject command line script into the page.
  981.         var scriptSource = getResource("chrome://firebug/content/commandLineInjected.js");
  982.         var addedElement = addScript(doc, "_firebugCommandLineInjector", scriptSource);
  983.     },
  984.  
  985.     addCommandLineListener: function(context, win, doc)
  986.     {
  987.         // Register listener for command-line execution events.
  988.         var handler = new CommandLineHandler(context, win);
  989.         var element = Firebug.Console.getFirebugConsoleElement(context, win);
  990.         element.addEventListener("firebugExecuteCommand", bind(handler.handleEvent, handler) , true);
  991.     }
  992. };
  993.  
  994. function CommandLineHandler(context, win)
  995. {
  996.     this.handleEvent = function(event)  // win is the window the handler is bound into
  997.     {
  998.         var baseWindow = context.baseWindow? context.baseWindow : context.window;
  999.         this.api = new FirebugCommandLineAPI(context,  baseWindow.wrappedJSObject);
  1000.  
  1001.         var htmlPanel = context.getPanel("html", true);
  1002.         var vars = htmlPanel?htmlPanel.getInspectorVars():null;
  1003.         for (var prop in vars)
  1004.         {
  1005.             function createHandler(p) {
  1006.                 return function() {
  1007.                     return vars[p] ? vars[p].wrappedJSObject : null;
  1008.                 }
  1009.             }
  1010.             this.api[prop] = createHandler(prop);  // XXXjjb should these be removed?
  1011.         }
  1012.  
  1013.         if (!Firebug.CommandLine.CommandHandler.handle(event, this.api, win))
  1014.         {
  1015.             var methodName = event.target.getAttribute("methodName");
  1016.             Firebug.Console.log($STRF("commandline.MethodNotSupported", [methodName]));
  1017.         }
  1018.     };
  1019. }
  1020.  
  1021. function getNoScript()
  1022. {
  1023.     if (!this.noscript)
  1024.         this.noscript = Cc["@maone.net/noscript-service;1"] &&
  1025.             Cc["@maone.net/noscript-service;1"].getService().wrappedJSObject;
  1026.     return this.noscript;
  1027. }
  1028.  
  1029. // ************************************************************************************************
  1030.  
  1031. Firebug.registerModule(Firebug.CommandLine);
  1032.  
  1033. // ************************************************************************************************
  1034.  
  1035. }});
  1036.